/*
 * File:         Destination.java
 * Author:       Robert Bittle <guywithnose@gmail.com>
 */
package triperest;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;

import org.json.JSONObject;
import org.json.JSONString;

/**
 * The Class Destination.
 */
public class Destination implements DataObject, JSONString {

	/** The ID. */
	private long ID = 0;

	/** The name. */
	private String name;

	/** The rank. */
	private int rank;

	/** The reviews. */
	private ArrayList<Review> reviews = new ArrayList<Review>();

	/** The places id. */
	private String placesId;

	/**
	 * Get ID.
	 *
	 * @return the ID
	 */
	public long getID() {
		return this.ID;
	}

	/**
	 * Instantiates a new destination.
	 *
	 * @param id the id
	 */
	public Destination(long id) {
		ID = id;
		load();
	}

	/**
	 * Instantiates a new destination.
	 */
	public Destination() {
	}

	/**
	 * Get Name.
	 *
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name.
	 *
	 * @param Name the new name
	 */
	public void setName(String Name) {
		this.name = Name;
	}

	/**
	 * Get Rank.
	 *
	 * @return the rank
	 */
	public Integer getRank() {
		return rank;
	}

	/**
	 * Sets the rank.
	 *
	 * @param Rank the new rank
	 */
	public void setRank(Integer Rank) {
		this.rank = Rank;
	}

	/**
	 * Get Places id.
	 *
	 * @return the places id
	 */
	public String getPlacesId() {
		return placesId;
	}

	/**
	 * Sets the places id.
	 *
	 * @param PlacesId the new places id
	 */
	public void setPlacesId(String PlacesId) {
		this.placesId = PlacesId;
	}

	/**
	 * Get Reviews.
	 *
	 * @return the reviews
	 */
	public ArrayList<Review> getReviews() {
		return this.reviews;
	}

	/**
	 * Adds the review.
	 *
	 * @param review the review
	 */
	public void addReview(Review review) {
		if (!this.reviews.contains(review)) {
			this.reviews.add(review);
		}
		// recalculate the rank based on comments
		int localRank = 0;
		for (int i = 0; i < this.reviews.size(); i++) {
			localRank += this.reviews.get(i).rank;
		}
		this.rank = localRank / this.reviews.size();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see triperest.DataObject#delete()
	 */
	@Override
	public boolean delete() {
		try {
			if (DataConnection.connect()) {
				String statement = "delete from dest where dest_id = ?";
				PreparedStatement stmt = DataConnection.getConnection()
						.prepareStatement(statement);
				stmt.setLong(1, ID);
				int success = 2;
				stmt.executeUpdate();
				Iterator<Long> j = loadReviewIds().iterator();
				while (j.hasNext()) {
					deleteReviewId(j.next());
				}
				return success == 1;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see triperest.DataObject#save()
	 */
	@Override
	public boolean save() {
		try {

			if (ID != 0) {
				return update();
			}
			return insert();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * Update.
	 * 
	 * @return true, if successful
	 * @throws SQLException
	 *             the SQL exception
	 */
	private boolean update() throws SQLException {
		if (DataConnection.connect()) {
			String statement = "update dest set name = ?, places_id = ?, rank = ? where dest_id = ?";
			PreparedStatement stmt = DataConnection.getConnection()
					.prepareStatement(statement);
			stmt.setString(1, name);
			stmt.setString(2, placesId);
			stmt.setInt(3, rank);
			stmt.setLong(4, ID);
			int success = 2;
			stmt.executeUpdate();
			saveReviews();
			return success == 1;
		}
		return false;
	}

	/**
	 * Update.
	 * 
	 * @return true, if successful
	 * @throws SQLException
	 *             the sQL exception
	 */
	private boolean insert() throws SQLException {
		if (DataConnection.connect()) {
			String statement = "INSERT INTO dest (name, rank, places_id) VALUES ( ? , ? , ? )";
			PreparedStatement stmt = DataConnection.getConnection()
					.prepareStatement(statement,
							Statement.RETURN_GENERATED_KEYS);
			stmt.setString(1, name);
			stmt.setInt(2, rank);
			stmt.setString(3, placesId);
			int success = 2;
			stmt.executeUpdate();
			ResultSet key = stmt.getGeneratedKeys();
			if (key.next()) {
				ID = key.getLong(1);
				saveReviews();
			}
			return success == 1;
		}
		return false;
	}

	/**
	 * Save reviews.
	 *
	 * @throws SQLException the sQL exception
	 */
	private void saveReviews() throws SQLException {
		ArrayList<Long> reviewIds = loadReviewIds();
		Iterator<Review> i = reviews.iterator();
		while (i.hasNext()) {
			Review review = i.next();
			review.save();
			if (reviewIds.contains(review.getId())) {
				reviewIds.remove(review.getId());
			} else {
				saveReviewId(review.getId());
			}
		}
		Iterator<Long> j = reviewIds.iterator();
		while (j.hasNext()) {
			deleteReviewId(j.next());
		}
	}

	/**
	 * Save review id.
	 *
	 * @param reviewId the review id
	 * @throws SQLException the sQL exception
	 */
	private void saveReviewId(long reviewId) throws SQLException {
		if (DataConnection.connect()) {
			String statement = "INSERT INTO dest_review (dest_id, review_id) VALUES ( ? , ? )";
			PreparedStatement stmt = DataConnection.getConnection()
					.prepareStatement(statement);
			stmt.setLong(1, ID);
			stmt.setLong(2, reviewId);
			stmt.executeUpdate();
		}
	}

	/**
	 * Delete review id.
	 *
	 * @param reviewId the review id
	 * @throws SQLException the sQL exception
	 */
	private void deleteReviewId(long reviewId) throws SQLException {
		if (DataConnection.connect()) {
			String statement = "delete from dest_review where dest_id = ? and review_id = ?";
			PreparedStatement stmt = DataConnection.getConnection()
					.prepareStatement(statement);
			stmt.setLong(1, ID);
			stmt.setLong(2, reviewId);
			stmt.executeUpdate();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see triperest.DataObject#load()
	 */
	@Override
	public boolean load() {
		try {
			if (DataConnection.connect()) {
				String statement = "select name, rank, places_id from dest where dest_id = ?";
				PreparedStatement stmt = DataConnection.getConnection()
						.prepareStatement(statement);
				stmt.setLong(1, ID);
				ResultSet results = stmt.executeQuery();
				if (results.next()) {
					name = results.getString("name");
					rank = results.getInt("rank");
					placesId = results.getString("places_id");
					Iterator<Long> i = loadReviewIds().iterator();
					while (i.hasNext()) {
						reviews.add(new Review(i.next()));
					}
					return true;
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * Load review ids.
	 *
	 * @return the array list
	 */
	private ArrayList<Long> loadReviewIds() {
		ArrayList<Long> reviewIds = new ArrayList<Long>();
		try {
			if (DataConnection.connect()) {
				String statement = "select review_id from dest_review where dest_id = ?";
				PreparedStatement stmt = DataConnection.getConnection()
						.prepareStatement(statement);
				stmt.setLong(1, ID);
				ResultSet results = stmt.executeQuery();
				while (results.next()) {
					reviewIds.add(results.getLong("review_id"));
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return reviewIds;
	}
	
	/**
	 * Get All destinations.
	 *
	 * @return the all destinations
	 */
	public static String getAllDestinations()
	{
		ArrayList<Destination> destinations = new ArrayList<Destination>();
		try {
			if (DataConnection.connect()) {
				String statement = "select dest_id from dest";
				PreparedStatement stmt = DataConnection.getConnection()
						.prepareStatement(statement);
				ResultSet results = stmt.executeQuery();
				while (results.next()) {
					destinations.add(new Destination(results.getLong("dest_id")));
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return JSONObject.wrap(destinations).toString();
	}

	/* (non-Javadoc)
	 * @see org.json.JSONString#toJSONString()
	 */
	@Override
	public String toJSONString() {
		return "{\""+"name\":\""+name+"\",\""+"content\":\""+name+"\"}";
	}

}
